package io.xxx.omni.sync.impl

import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
import com.suning.api.DefaultSuningClient
import com.suning.api.SuningRequest
import com.suning.api.SuningResponse
import com.suning.api.entity.custom.RefundlistinformationQueryRequest
import com.suning.api.entity.custom.RefundlistinformationQueryResponse
import com.suning.api.entity.transaction.OrderQueryRequest
import com.suning.api.entity.transaction.OrderQueryResponse
import io.xxx.omni.sync.Document
import io.xxx.omni.sync.PagePorter
import io.xxx.omni.sync.Store
import io.xxx.omni.util.dateTimeFormatter
import io.xxx.omni.util.toLocalDateTime
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component
import java.time.Duration
import java.time.LocalDateTime

/**
 * 苏宁
 */
abstract class SnPorter<R : SuningResponse> : PagePorter() {

    private val httpUrl = "https://open.suning.com/api/http/sopRequest"

    override val platformCode = "suning"

    override val duration: Duration? = Duration.ofDays(30)

    protected fun getResponse(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        pageNo: Long = 1,
    ): R {
        var client = container["snClient"]
        if (client == null) {
            client = DefaultSuningClient(httpUrl, store.appKey, store.appSecret, "json")
            container["snClient"] = client
        }

        val request = buildRequest(startTime, endTime, pageNo)
        val response = (client as DefaultSuningClient).excute(request)
        if (response.code != "0") {
            val msg = "接口[method: ${request.appMethod}]异常: ${response.body}"
            log.error(msg)
            throwException(request.appMethod, response.code, response.body)
        }
        return response
    }

    protected abstract fun buildRequest(
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        pageNo: Long,
    ): SuningRequest<R>

    companion object {
        private val log = LoggerFactory.getLogger(SnPorter::class.java)
    }
}

@Component
class SnTradePorter : SnPorter<OrderQueryResponse>() {

    override val jobId = 1

    override fun getCount(store: Store, startTime: LocalDateTime, endTime: LocalDateTime, parameter: Any?): Long? {
        val response = getResponse(store, startTime, endTime)
        return response.snhead.totalSize.toLong()
    }

    override fun getData(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        parameter: Any?,
        pageNo: Long
    ): List<Document> {
        val response = getResponse(store, startTime, endTime)
        return response.snbody.orderQuery.map {
            Document(it.orderCode, JSON.toJSON(it) as JSONObject, it.orderSaleTime.toLocalDateTime())
        }
    }

    override fun buildRequest(
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        pageNo: Long
    ): SuningRequest<OrderQueryResponse> {
        val request = OrderQueryRequest()
        request.startTime = startTime.format(dateTimeFormatter)
        request.endTime = endTime.format(dateTimeFormatter)
        request.setPageSize(pageSize)
        request.setPageNo(pageNo.toInt())
        return request
    }
}

@Component
class SnRefundPorter : SnPorter<RefundlistinformationQueryResponse>() {

    override val jobId = 1

    override fun getCount(store: Store, startTime: LocalDateTime, endTime: LocalDateTime, parameter: Any?): Long? {
        val response = getResponse(store, startTime, endTime)
        return response.snhead.totalSize.toLong()
    }

    override fun getData(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        parameter: Any?,
        pageNo: Long
    ): List<Document> {
        val response = getResponse(store, startTime, endTime)
        return response.snbody.queryRefundlistinformation
            .flatMap { it.returnList }
            .map {
                Document(it.returnApplyId, it.orderNo, JSON.toJSON(it) as JSONObject, it.operateTime.toLocalDateTime())
            }
    }

    override fun buildRequest(
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        pageNo: Long
    ): SuningRequest<RefundlistinformationQueryResponse> {
        val request = RefundlistinformationQueryRequest()
        request.startModified = startTime.format(dateTimeFormatter)
        request.endModified = endTime.format(dateTimeFormatter)
        request.setPageSize(pageSize)
        request.setPageNo(pageNo.toInt())
        return request
    }
}